package copyengine.network.serverAgent.impl.socket.dataHandle
{
    import flash.events.ProgressEvent;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import flash.utils.Endian;

    /**
     * 对如下种类的数据包格式进行解析支持
     *
     * 包儿的长度           ->4个字节的int
     * Command命令    ->4个字节的int
     * 包儿主体
     *
     * 注意 假设读到的包儿长度是10  表示包儿主体的长度是10个字节 Command不算在内
     */
    public class ServerAgentSocketCommandModelDataHandle implements IServerAgentSocketConnectorDataHandle
    {
        private var mReceiveServerDataCallback:Function;
        private var mBufferByteArray:ByteArray;
        private var mTempBufferByteArray:ByteArray;

        public function ServerAgentSocketCommandModelDataHandle()
        {
            mBufferByteArray = new ByteArray();
            mBufferByteArray.endian = Endian.BIG_ENDIAN;

            mTempBufferByteArray = new ByteArray();
            mTempBufferByteArray.endian = Endian.BIG_ENDIAN;
        }

        public function set onReceiveServerDataCallback(_callback:Function):void {mReceiveServerDataCallback = _callback;}

        public function handleData(_socket:Socket, e:ProgressEvent):void
        {
            //将新的数据流添加到当前没有读取的数据尾端
            _socket.readBytes(mBufferByteArray, mBufferByteArray.length, _socket.bytesAvailable)
            readPackage();
        }

        private function readPackage():void
        {
            if (mBufferByteArray.bytesAvailable >= 4) {
                //readInt先读出4字节是包儿体的长度
                //长度后面放的是一个4字节的Command 所以读到的长度要+4
                var packageLength:int = mBufferByteArray.readUnsignedInt();
                if (mBufferByteArray.bytesAvailable >= packageLength + 4) {
                    //当前剩余字节足够解析出来一个数据包的

                    //==============
                    //==解析出完整的数据包
                    //==============
                    var command:int = mBufferByteArray.readUnsignedInt();
                    var packageDataByteArray:ByteArray = new ByteArray();
                    //使用mBufferByteArray.readBytes 而不是 arg.writeByte 是因为readyByte以后其position会发生变化
                    //从而mBufferByteArray.bytesAvailable才能指向剩余没有读取的字节数
                    //readBytes用法:
                    //mBufferByteArray.readBytes(packageDataByteArray, 0, packageLength);
                    //表示从mBufferByteArray当前position读取packageLength个字节到arg这个ByteArray中(从packageDataByteArray的0号位置开始写入)
                    //同时mBufferByteArray的position会向后偏移packageLength个字节 并且bytesAvailable也会减少相应的字节数
                    mBufferByteArray.readBytes(packageDataByteArray, 0, packageLength);
                    mReceiveServerDataCallback && mReceiveServerDataCallback(command, packageDataByteArray);

                    if (mBufferByteArray.bytesAvailable > 0) {
                        //读取一个数据包后还有剩余(粘包儿)

                        //将剩余的数据重新整理出来然后递归再继续解析
                        //writeBytes用法:
                        //mTempBufferByteArray.writeBytes(mBufferByteArray,mBufferByteArray.position, mBufferByteArray.bytesAvailable);
                        //表示将mBufferByteArray中从position开始bytesAvailable这么多个字节写到mTempBufferByteArray中
                        mTempBufferByteArray.writeBytes(mBufferByteArray, mBufferByteArray.position, mBufferByteArray.bytesAvailable);
                        swapAndResetBuffer();
                        readPackage();
                        return;
                    }
                } else {
                    //当前数据包不足以读出一个包儿(断包儿)
                    //将读出来的长度重新Push回ByteArray
                    //然后将剩余的字节数也Push回去, 这样Temp中的数据包就"还原"成原始的了
                    //return 等到新的数据到来
                    mTempBufferByteArray.writeInt(packageLength);
                    mTempBufferByteArray.writeBytes(mBufferByteArray, mBufferByteArray.position, mBufferByteArray.bytesAvailable);
                    swapAndResetBuffer();
                    return;
                }
            } else {
                //当前剩余字节连长度都读不出来 直接return 等待新的数据
                return;
            }
        }

        public function dispose():void
        {
        }

        private function swapAndResetBuffer():void
        {
            var swapByteArray:ByteArray = mTempBufferByteArray;
            mTempBufferByteArray = mBufferByteArray;
            mBufferByteArray = swapByteArray;

            mBufferByteArray.position = 0;
            mTempBufferByteArray.clear();
        }


    }
}
